package com.ls.demo.tcp.service.impl;

import com.ls.demo.bean.Command;
import com.ls.demo.enums.CommandTypeEnum;
import com.ls.demo.enums.MessageAttrEnum;
import com.ls.demo.http.service.DownloadService;
import com.ls.demo.tcp.namespace.Namespaces;
import com.ls.demo.tcp.service.CommandService;
import com.ls.demo.tcp.service.DispatcherCommand;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author liShan
 * @date 2019/8/31 9:51
 */
@Service
@Log
public class DispatcherCommandImpl implements DispatcherCommand {

    @Resource
    private Map<String, CommandService> commandServiceMap;

    @Resource
    private Map<String, DownloadService> downloadServiceMap;

    private Namespaces namespaces = Namespaces.getInstance();

    @Override
    public void uploadCommand(final ChannelHandlerContext ctx, final Command command) {
        Command c = null;
        log.info(String.format("[%s]接收到的命令", command.getCommand()));
        // 先应答
        AttributeKey<Boolean> identity = AttributeKey.valueOf("identity");
        if (MessageAttrEnum.HEARTBEAT_CHECK.getMessageAttr().equals(command.getMessageAttr().toUpperCase())){
            c = commandServiceMap.get("command_0A").execute(ctx, command);
            // 判断是否进行了身份认证
            if (!ctx.channel().attr(identity).get()){
                // 表示没有进行身份的询问
                this.identity(ctx, c);
            }
        }else {
            if (MessageAttrEnum.IDENTITY_INQUIRY.getMessageAttr().equals(command.getMessageAttr().toUpperCase())){
                c = commandServiceMap.get("command_0E").execute(ctx, command);
            }
            // 判断是否进行了身份认证
            if (ctx.channel().attr(identity).get()){
                for (String str : commandServiceMap.keySet()) {
                    if (str.endsWith(command.getMessageAttr().toUpperCase())){
                        c = commandServiceMap.get(str).execute(ctx, command);
                        break;
                    }
                }
            }
        }
        if (null != c){
            this.download(c);
            String co = c.getCommandVal();
            log.info(String.format("[%s]应答的命令", co));
            this.resposned(ctx, co);
        }
    }

    /**
     * 拼接身份询问请求，并发送
     * @param command 包含地址等信息
     * @param ctx 通道
     */
    private void identity(ChannelHandlerContext ctx, Command command){
        command.setMessageAttr(MessageAttrEnum.IDENTITY_INQUIRY.getMessageAttr());
        command.setDataList(Stream.of("00").collect(Collectors.toList()));
        String co = command.getCommandVal();
        log.info(String.format("[%s]身份询问的命令", co));
        this.resposned(ctx, co);
    }

    /**
     * 下载信息拼接
     * @param command 命令
     */
    private void download(Command command){
        command.setHeader(CommandTypeEnum.DOWNLOAD.getHeader());
        command.setTail(CommandTypeEnum.DOWNLOAD.getTail());
    }

    @Override
    public void downloadCommand(String str, String uri) {
        String type = uri.substring(uri.lastIndexOf("/"));
        Set<String> keys = downloadServiceMap.keySet();
        Command command = new Command();
        String boxId = "";
        for (String key : keys) {
            if (key.endsWith(String.format("_%s", type))){
                boxId = downloadServiceMap.get(key).execute(str, command);
            }
        }
        String co = command.getCommandVal();
        log.info(String.format("[%s]应答的命令", co));
        this.resposned(namespaces.getChannel(boxId), co);
    }

    /**
     * 进行响应
     * @param ctx 通道
     * @param command 命令
     */
    private void resposned(ChannelHandlerContext ctx, String command){
        if (StringUtils.isNotBlank(command) && null != ctx){
            String[] strs = command.split("\\s");
            byte[] bytes = new byte[strs.length];
            for(int i = 0; i < strs.length; i++) {
                bytes[i] = (byte) Integer.parseInt(strs[i], 16);
            }
            ctx.writeAndFlush(Unpooled.copiedBuffer(bytes));
        }
    }

}
